﻿// Copyright (c) Microsoft Open Technologies, Inc. All rights reserved. See License.txt in the project root for license information.

namespace Microsoft.Data.Entity.Design.Model.Mapping
{
    using System.Collections.Generic;
    using System.Diagnostics;
    using System.Globalization;
    using System.Xml.Linq;

    internal class ModificationFunctionMapping : EFElement
    {
        internal static readonly string ElementName = "ModificationFunctionMapping";

        private DeleteFunction _deleteFunction;
        private InsertFunction _insertFunction;
        private UpdateFunction _updateFunction;

        internal ModificationFunctionMapping(EntityTypeMapping parent, XElement element)
            : base(parent, element)
        {
        }

        internal EntityTypeMapping EntityTypeMapping
        {
            get
            {
                var parent = Parent as EntityTypeMapping;
                Debug.Assert(parent != null, "this.Parent should be a EntityTypeMapping");
                return parent;
            }
        }

        internal DeleteFunction DeleteFunction
        {
            get { return _deleteFunction; }
            set { _deleteFunction = value; }
        }

        internal InsertFunction InsertFunction
        {
            get { return _insertFunction; }
            set { _insertFunction = value; }
        }

        internal UpdateFunction UpdateFunction
        {
            get { return _updateFunction; }
            set { _updateFunction = value; }
        }

        // we unfortunately get a warning from the compiler when we use the "base" keyword in "iterator" types generated by using the
        // "yield return" keyword.  By adding this method, I was able to get around this.  Unfortunately, I wasn't able to figure out
        // a way to implement this once and have derived classes share the implementation (since the "base" keyword is resolved at 
        // compile-time and not at runtime.
        private IEnumerable<EFObject> BaseChildren
        {
            get { return base.Children; }
        }

        internal override IEnumerable<EFObject> Children
        {
            get
            {
                foreach (var efobj in BaseChildren)
                {
                    yield return efobj;
                }

                if (DeleteFunction != null)
                {
                    yield return DeleteFunction;
                }
                if (InsertFunction != null)
                {
                    yield return InsertFunction;
                }
                if (UpdateFunction != null)
                {
                    yield return UpdateFunction;
                }
            }
        }

        protected override void OnChildDeleted(EFContainer efContainer)
        {
            if (efContainer == _deleteFunction)
            {
                _deleteFunction = null;
                return;
            }

            if (efContainer == _insertFunction)
            {
                _insertFunction = null;
                return;
            }

            if (efContainer == _updateFunction)
            {
                _updateFunction = null;
                return;
            }

            base.OnChildDeleted(efContainer);
        }

#if DEBUG
        internal override ICollection<string> MyAttributeNames()
        {
            var s = base.MyAttributeNames();
            return s;
        }
#endif

#if DEBUG
        internal override ICollection<string> MyChildElementNames()
        {
            var s = base.MyChildElementNames();
            s.Add(DeleteFunction.ElementName);
            s.Add(InsertFunction.ElementName);
            s.Add(UpdateFunction.ElementName);
            return s;
        }
#endif

        protected override void PreParse()
        {
            Debug.Assert(State != EFElementState.Parsed, "this object should not already be in the parsed state");

            ClearEFObject(_deleteFunction);
            _deleteFunction = null;

            ClearEFObject(_insertFunction);
            _insertFunction = null;

            ClearEFObject(_updateFunction);
            _updateFunction = null;

            base.PreParse();
        }

        private string DisplayNameInternal(bool localize)
        {
            string resource;
            string etmDisplayName;
            if (localize)
            {
                resource = Resources.MappingModel_ModificationFunctionMappingDisplayName;
                etmDisplayName = EntityTypeMapping.DisplayName;
            }
            else
            {
                resource = "ModificationFunctionMapping for {0}";
                etmDisplayName = EntityTypeMapping.NonLocalizedDisplayName;
            }

            return string.Format(CultureInfo.CurrentCulture, resource, etmDisplayName);
        }

        internal override string DisplayName
        {
            get { return DisplayNameInternal(true); }
        }

        internal override string NonLocalizedDisplayName
        {
            get { return DisplayNameInternal(false); }
        }

        internal override bool ParseSingleElement(ICollection<XName> unprocessedElements, XElement elem)
        {
            if (elem.Name.LocalName == DeleteFunction.ElementName)
            {
                _deleteFunction = new DeleteFunction(this, elem);
                _deleteFunction.Parse(unprocessedElements);
            }
            else if (elem.Name.LocalName == InsertFunction.ElementName)
            {
                _insertFunction = new InsertFunction(this, elem);
                _insertFunction.Parse(unprocessedElements);
            }
            else if (elem.Name.LocalName == UpdateFunction.ElementName)
            {
                _updateFunction = new UpdateFunction(this, elem);
                _updateFunction.Parse(unprocessedElements);
            }
            else
            {
                return base.ParseSingleElement(unprocessedElements, elem);
            }
            return true;
        }
    }
}
